package com.lingjtx.common.other.helper;

import com.alibaba.fastjson2.JSON;
import com.lingjtx.common.core.RedisOptions;
import com.lingjtx.common.core.algorithm.Algorithm;
import com.lingjtx.common.core.constant.CodeMessage;
import com.lingjtx.common.core.constant.Const;
import com.lingjtx.common.core.constant.SmsTemplate;
import com.lingjtx.common.core.constant.WeXinTemplate;
import com.lingjtx.common.core.handle.ObjectPool;
import com.lingjtx.common.core.util.DateTimeUtil;
import com.lingjtx.common.core.util.LinkGenerator;
import com.lingjtx.common.core.util.LinkGeneratorHandler;
import com.lingjtx.common.core.util.StringUtil;
import com.lingjtx.common.other.model.sms.CodeTemplate;
import com.lingjtx.common.other.model.sms.SmsRequest;
import com.lingjtx.common.other.model.weixin.TemplateContent;
import com.lingjtx.common.other.model.weixin.WeiXinTemplateDateParam;
import com.lingjtx.common.other.model.weixin.WeiXinTemplateMsgRequest;
import jakarta.mail.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.thymeleaf.TemplateEngine;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * 消息管理器
 * 发送平台：手机短信、邮箱、微信通知
 * 消息内容：验证码、活动结果、推广等
 * <p>
 * 此外有验证功能，对外提供验证方法
 * <p>
 * 特例：手机验证码、邮箱激活
 *
 * @author John Liu
 */
public enum MessageManager {

    INSTANCE;

    private static final Logger log = LoggerFactory.getLogger(MessageManager.class);

    public MessageManager.Builder init() {
        return new MessageManager.Builder();
    }

    /**
     * 校验验证码
     *
     * @param receiver 接收者
     * @param code     验证码
     * @param redis
     * @return true: 有效的；false：无效
     */
    public boolean valid(String receiver, String code, RedisOptions redis) {
        if (Objects.equals(code, redis.get(receiver))) {
            redis.delete(receiver);
            return true;
        }
        return false;
    }

    // 发送验证码
    public void sendCode(String receiver, MessagePlatform platform, CodeMessage codeMessage, RedisOptions redis, ObjectPool<?> objectPool, TemplateEngine engine) {
        // 缓存验证码
        String smsCode = StringUtil.randomCode(6);
        redis.set(receiver, smsCode, codeMessage.getTime());
        log.info("===========验证码：{}==============", smsCode);
        if (MessagePlatform.SMS.equals(platform)) {
            // 跳过测试账号
            String TEST_MOBILE = Const.TEST_MOBILE;
            if (TEST_MOBILE != null) {
                for (String mobile : TEST_MOBILE.split(",")) {
                    if (mobile.equals(receiver)) {
                        redis.set(receiver, "123456", codeMessage.getTime());
                        return;
                    }
                }
            }
            CodeTemplate codeTemplate = new CodeTemplate();
            codeTemplate.setMsg(smsCode);
            MessageManager.INSTANCE.init()
                    .withPlatform(MessagePlatform.SMS)
                    .withReceiver(Collections.singletonList(receiver))
                    .withSmsTemplate(SmsTemplate.VERIFICATION_CODE)
                    .withContent(codeTemplate)
                    .withObjectPool(objectPool)
                    .send();
        } else if (MessagePlatform.MAIL.equals(platform)) {
            TemplateEntity<Object> template = new TemplateEntity<>();
            template.setTemplateEngine(engine);
            template.setCode(smsCode);
            template.setMsg(codeMessage.getMsg());
            HtmlTemplate.CODE_MESSAGE.setTemplate(template);
            MessageManager.INSTANCE.init()
                    .withPlatform(MessagePlatform.MAIL)
                    .withReceiver(Collections.singletonList(receiver))
                    .withMailSubject("验证码")
                    .withContent(HtmlTemplate.CODE_MESSAGE)
                    .withObjectPool(objectPool)
                    .send();
        } else if (MessagePlatform.WEXIN.equals(platform)) {
            MessageManager.INSTANCE.init()
                    .withPlatform(MessagePlatform.WEXIN)
                    .withReceiver(Collections.singletonList(receiver))
                    .withWeXinTemplate(WeXinTemplate.VERIFICATION_CODE)
                    .withContent(smsCode + codeMessage.getMsg())
                    .withRedis(redis)
                    .withObjectPool(objectPool)
                    .send();
        }
    }

    // 邮箱激活
    public void activeEmail(String receiver,
                            Object data,
                            Algorithm algorithm,
                            LinkGeneratorHandler handler,
                            RedisOptions redis,
                            ObjectPool<Session> objectPool,
                            TemplateEngine engine) {

        LinkGenerator linkGenerator = LinkGenerator.init()
                .setLinkGeneratorHandler(handler)
                .setAlgorithm(algorithm)
                .setBaseurl(Const.SERVER_URL)
                .setUri("/user/verify/mail_account")
                .setChecks(1L)
                .setData(receiver)
                .setData(data)
                .setRedisOptions(redis)
                .build();

        TemplateEntity<Object> template = new TemplateEntity<>();
        template.setTemplateEngine(engine);
        template.setData(data);
        template.setCode(linkGenerator.generator());
        HtmlTemplate.ACTIVE_EMAIL.setTemplate(template);

        MessageManager.INSTANCE.init()
                .withReceiver(Collections.singletonList(receiver))
                .withMailSubject("邮箱验证确认")
                .withPlatform(MessagePlatform.MAIL)
                .withContent(HtmlTemplate.ACTIVE_EMAIL)
                .withObjectPool(objectPool)
                .send();
    }

    public void activeEmail(String receiver,
                            Object data,
                            RedisOptions redis,
                            ObjectPool<Session> objectPool,
                            TemplateEngine engine) {
        activeEmail(receiver, data, Algorithm.RANDOM, new LinkGenerator.RestfulPolicy(), redis, objectPool, engine);
    }

    private void send(MessageManager.Builder builder) {
        MessageContext context = new MessageContext();
        context.setContexts(new SmsPolicy());
        context.setContexts(new MailPolicy());
        context.setContexts(new WeChatPolicy());
        context.process(builder);
    }

    public static final class Builder {
        private List<String> receiver;

        private Object content;

        private MessagePlatform platform;

        private SmsTemplate smsTemplate;

        private WeXinTemplate weXinTemplate;

        private String mailSubject;

        private RedisOptions redisOptions;

        private ObjectPool objectPool;

        public MessageManager.Builder withReceiver(List<String> receiver) {
            this.receiver = receiver;
            return this;
        }

        public MessageManager.Builder withContent(Object content) {
            this.content = content;
            return this;
        }

        public MessageManager.Builder withPlatform(MessagePlatform platform) {
            this.platform = platform;
            return this;
        }

        public MessageManager.Builder withSmsTemplate(SmsTemplate smsTemplate) {
            this.smsTemplate = smsTemplate;
            return this;
        }

        public MessageManager.Builder withWeXinTemplate(WeXinTemplate weXinTemplate) {
            this.weXinTemplate = weXinTemplate;
            return this;
        }

        public MessageManager.Builder withMailSubject(String mailSubject) {
            this.mailSubject = mailSubject;
            return this;
        }

        public MessageManager.Builder withRedis(RedisOptions redis) {
            this.redisOptions = redis;
            return this;
        }

        public MessageManager.Builder withObjectPool(ObjectPool objectPool) {
            this.objectPool = objectPool;
            return this;
        }

        public void send() {
            if (receiver == null || receiver.isEmpty() || content == null || platform == null) {
                throw new NullPointerException("receiver, content, platform is null!");
            }
            // 异步发送
            objectPool.async(() -> MessageManager.INSTANCE.send(this));
        }
    }

    public enum MessagePlatform {
        SMS,
        MAIL,
        WEXIN
    }

    private static class MessageContext {

        private final List<MessageHandler> contexts = new ArrayList<>();

        public void setContexts(MessageHandler handler) {
            contexts.add(handler);
        }

        public void process(MessageManager.Builder builder) {
            contexts.forEach((handler) -> {
                if (handler.getPlatform().equals(builder.platform)) {
                    handler.send(builder);
                }
            });
        }
    }

    private static class SmsPolicy implements MessageHandler {

        @Override
        public MessagePlatform getPlatform() {
            return MessagePlatform.SMS;
        }

        @Override
        public void send(MessageManager.Builder builder) {
            if (builder.objectPool == null) throw new NullPointerException("objectPool is null!");
            String mobile = String.join(",", builder.receiver);
            SmsRequest requestModel = new SmsRequest();
            requestModel.setPhoneNumbers(mobile);
            requestModel.setSmsTemplate(Objects.requireNonNullElse(builder.smsTemplate, SmsTemplate.DEFAULT));
            requestModel.setTemplateParam(JSON.toJSONString(builder.content));
            SmsHelper.sendSms(requestModel, builder.objectPool);
        }
    }

    private static class MailPolicy implements MessageHandler {

        @Override
        public MessagePlatform getPlatform() {
            return MessagePlatform.MAIL;
        }

        @Override
        public void send(MessageManager.Builder builder) {
            MailHelper.init()
                    .withObjectPoolTemplate(builder.objectPool)
                    .withSubject(builder.mailSubject)
                    .withContent(builder.content.toString())
                    .withReceivers(builder.receiver)
                    .send();
        }
    }

    private static class WeChatPolicy implements MessageHandler {

        @Override
        public MessagePlatform getPlatform() {
            return MessagePlatform.WEXIN;
        }

        @Override
        public void send(MessageManager.Builder builder) {
            if (builder.redisOptions == null) throw new NullPointerException("redisOptions is null!");
            if (builder.objectPool == null) throw new NullPointerException("objectPool is null!");
            WeiXinTemplateMsgRequest request = new WeiXinTemplateMsgRequest();
            request.setTemplate_id(builder.weXinTemplate.toString());
            request.setUrl("");
            WeiXinTemplateDateParam param = new WeiXinTemplateDateParam();
            TemplateContent content1 = new TemplateContent(builder.weXinTemplate.getTitle());
            param.setFirst(content1);

            TemplateContent content2 = new TemplateContent(builder.content.toString());
            param.setKeyword1(content2);

            TemplateContent content3 = new TemplateContent(DateTimeUtil.getDateStr());
            param.setKeyword2(content3);

            TemplateContent content4 = new TemplateContent("如非本人操作，请忽略此消息");
            param.setRemark(content4);

            request.setData(param);

            builder.receiver.forEach(e -> {
                request.setClient_msg_id(Algorithm.UUID.toString());
                request.setTouser(e);
                WeiXinHelper.send(request, builder.redisOptions, builder.objectPool);
            });

        }
    }
}
